
package view;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Vector;

import util.BookData;
import util.BookUtil;

import com.oahc.bookreaderone.MainActivity;
import com.oahc.bookreaderone.R;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Toast;

public class BookPageFactory {
    private int mWidth;

    private int mHeight;

    private float m_fontSize = 24;

    private int marginWidth = 15; // 左右与边缘的距离

    private int marginHeight = 65; // 上下与边缘的距离

    private float mVisibleHeight; // 绘制内容的宽

    private float mVisibleWidth; // 绘制内容的宽

    private int mLineCount; // 每页可以显示的行数

    private String m_strCharsetName = "UTF-8";

    private Paint mPaint;

    private int pageTxtCount;// 一页显示的字数

    Bitmap mCurPageBitmap, mNextPageBitmap, themeBitmap;

    Canvas mCurPageCanvas, mNextPageCanvas;

    private int m_mbBufLen = 0;// 总长度

    private int m_mbBufEnd = 0;

    MappedByteBuffer m_mbBuf;

    private int curPage = 0, totalPages;

    private String bookname = "";

    private int bookId;

    private int themeStyle;// 主题模式

    private static BookPageFactory instance;

    public static BookPageFactory getInstance() {
        return instance;
    }

    BookView bookview;

    View parent;

    public BookPageFactory(View parent, BookView bv, int bookid) {
        instance = this;
        bookview = bv;
        this.parent = parent;
        bookId = bookid;
        mWidth = MainActivity.getInstance().getScreenWidth();
        mHeight = MainActivity.getInstance().getScreenHeight();
        mCurPageBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        mNextPageBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        mCurPageCanvas = new Canvas(mCurPageBitmap);
        mNextPageCanvas = new Canvas(mNextPageBitmap);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        calculatePageTxtCount();
    }

    public void calculatePageTxtCount() {
        this.m_fontSize = BookData.getInstance().getFontSize(bookId);
        this.themeStyle = BookData.getInstance().getTheme(bookId);
        this.themeBitmap = BookUtil.zoomImage(BitmapFactory.decodeResource(MainActivity
                .getInstance().getResources(), style[themeStyle]), mWidth, mHeight);
        parent.setBackgroundResource(style[themeStyle]);
        bookview.setBackgroundResource(style[themeStyle]);
        mPaint.setTextAlign(Align.LEFT);
        mPaint.setTextSize(m_fontSize);
        mPaint.setColor(Color.BLACK);
        mVisibleWidth = mWidth - 2 * marginWidth;
        mVisibleHeight = mHeight - 2 * marginHeight;
        mLineCount = (int)(mVisibleHeight / m_fontSize); // 可显示的行数
        int columnCount = (int)(mVisibleWidth / m_fontSize);// 列数
        pageTxtCount = (columnCount) * (mLineCount);
        // Log.d("br", "pageTxtCount=" + pageTxtCount + ",c=" + columnCount +
        // ",l=" + mLineCount);
    }

    /**
     * MappedByteBuffer 只是一种特殊的 ByteBuffer ，即是ByteBuffer的子类。 MappedByteBuffer
     * 将文件直接映射到内存（这里的内存指的是虚拟内存，并不是物理内存，后面说证明这一点）。通常，可以映射整个文件，如果文件比较大的话可以分段进行映射.
     * 
     * @param strFilePath
     * @throws IOException
     */
    public void loadBook(String strFilePath, String bookName) throws IOException {
        bookname = bookName;
        File book_file = new File(strFilePath);
        long lLen = book_file.length();
        m_mbBufLen = (int)lLen;
        FileInputStream fis = new FileInputStream(book_file);
        FileChannel fc = fis.getChannel();
        m_mbBuf = fc.map(FileChannel.MapMode.READ_ONLY, 0, m_mbBufLen);
        fis.close();
        createLines(0, 2);
        onDraw();
    }

    /**
     * 读取下一段落
     * 
     * @param nFromPos 起始的位置
     * @return
     */
    protected byte[] readParagraphForward(int nFromPos) {
        int nStart = nFromPos;
        int i = nStart;
        byte b0;
        // 根据编码格式判断换行-默认UTF-8的编码格式
        while (i < m_mbBufLen) {
            b0 = m_mbBuf.get(i++);
            if (b0 == 0x0a) {
                break;
            }
        }
        int nParaSize = i - nStart;// 段落的大小
        byte[] buf = new byte[nParaSize];
        for (i = 0; i < nParaSize; i++) {
            buf[i] = m_mbBuf.get(nFromPos + i);// 读取数据
        }
        return buf;
    }

    @SuppressLint("UseSparseArrays")
    HashMap<Integer, Vector<String>> linesMap = new HashMap<Integer, Vector<String>>();

    @SuppressLint("UseSparseArrays")
    private HashMap<Integer, Integer> mProgress = new HashMap<Integer, Integer>();

    /**
     * 创建文本行
     * 
     * @param i
     * @param end
     */
    public void createLines(int i, int end) {
        while (m_mbBufEnd < m_mbBufLen) {
            mProgress.put(i, m_mbBufEnd);
            linesMap.put(i, pageDown());
            Log.d("br", "m_mbBufEnd=" + m_mbBufEnd);
            if (i == end) {
                break;
            }
            i++;
        }
    }

    /**
     * 一次性加载完所有的行数据
     */
    public void createAllLines() {
        int p = 0;
        while (m_mbBufEnd < m_mbBufLen) {
            mProgress.put(p, m_mbBufEnd);
            linesMap.put(p, pageDown());
            p++;
        }
        this.totalPages = linesMap.size();
    }

    /**
     * 上一页
     */
    public void prePage() {
        if (curPage == 0) {
            Toast toast = Toast.makeText(MainActivity.getInstance(), "第一页", Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.CENTER, 0, 0);
            toast.show();
        } else {
            curPage--;
            onDraw();
        }

    }

    /**
     * 下一页
     */
    public void nextPage() {
        if (curPage >= linesMap.size()-1) {
            Toast toast = Toast.makeText(MainActivity.getInstance(), "最后一页", Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.CENTER, 0, 0);
            toast.show();
        }

        if (m_mbBufEnd < m_mbBufLen) {
            curPage++;
            if (curPage % 3 == 0 && curPage > this.linesMap.size() - 1) {
                createLines(curPage, curPage + 2);
            }
            onDraw();
        } else {
            curPage--;
        }
    }

    int[] style = new int[] {
            R.drawable.read_bg_1, R.drawable.read_bg_2, R.drawable.read_bg_3, R.drawable.read_bg_4
    };

    /**
     * 调节字体大小，需要重新加载一下
     */
    public void refreshBook(boolean theme) {
        if (theme) {
            this.themeStyle = BookData.getInstance().getTheme(bookId);
            this.themeBitmap = BookUtil.zoomImage(BitmapFactory.decodeResource(MainActivity
                    .getInstance().getResources(), style[themeStyle]), mWidth, mHeight);
            parent.setBackgroundResource(style[themeStyle]);
        } else {
            int processOld = this.mProgress.get(curPage);
            loadBookMark(0, curPage, processOld);
        }

        refreshView();
    }

    /**
     * 阅读界面刷新
     */
    public void refreshView() {
        this.onDraw();
        bookview.postInvalidate();
    }

    /**
     * 打开阅读前，加载书签
     */
    public void loadBookMark(int fromPage, int toPage, int processOld) {
        this.calculatePageTxtCount();
        if (toPage == 0) {
            toPage = 2;
        }
        this.linesMap.clear();
        this.mProgress.clear();
        m_mbBufEnd = 0;
        for (int i = fromPage; i <= toPage; i = i + 3) {
            int next = i + 2;
            createLines(i, next);
        }
        // 修正当前页码
        for (int i = 0; i < this.mProgress.size(); i++) {
            if (processOld < mProgress.get(i)) {
                curPage = i - 1;
                break;
            } else if (processOld == mProgress.get(i)) {
                curPage = i;
                break;
            }
        }
    }

    /**
     * 在离开阅读前保存当前的设置
     */
    public void saveSetting() {
        BookData.getInstance().saveFontSize(m_fontSize, bookId);
        BookData.getInstance().saveBookMark(new int[] {
                curPage, this.mProgress.get(curPage)
        }, bookId);
        BookData.getInstance().saveTheme(themeStyle, bookId);
    }

    /**
     * 翻页
     * 
     * @return 下一页的所有行数据
     */
    private Vector<String> pageDown() {
        String strParagraph = "";
        Vector<String> lines = new Vector<String>();
        while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) {
            byte[] paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落
            m_mbBufEnd += paraBuf.length;
            try {
                strParagraph = new String(paraBuf, m_strCharsetName);// 生成string
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            String strReturn = "";
            if (strParagraph.indexOf("\r\n") != -1) {
                strReturn = "\r\n";
                strParagraph = strParagraph.replaceAll("\r\n", "");
            } else if (strParagraph.indexOf("\n") != -1) {
                strReturn = "\n";
                strParagraph = strParagraph.replaceAll("\n", "");
            }

            if (strParagraph.length() == 0) {
                lines.add(strParagraph);
            }
            while (strParagraph.length() > 0) {
                int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth, null);// 每行可显示的最大的字数
                lines.add(strParagraph.substring(0, nSize));// 截取每行的数据
                strParagraph = strParagraph.substring(nSize);// 更新截取位置
                if (lines.size() >= mLineCount) {// 行满足
                    break;
                }
            }
            if (strParagraph.length() != 0) {
                try {
                    m_mbBufEnd -= (strParagraph + strReturn).getBytes(m_strCharsetName).length;
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        return lines;
    }

    private void onDraw() {
        drawCurPage();
    }

    DecimalFormat df = new DecimalFormat("##.##"); // 进度格式

    Matrix matrix = new Matrix();

    /**
     * 绘制当前页
     */
    private void drawCurPage() {
        if (this.themeBitmap == null) {
            mCurPageCanvas.drawColor(0xffff9e85);
        } else {
            mCurPageCanvas.drawBitmap(themeBitmap, 0, 0, mPaint);
        }
        int y = 25;
        for (String strLine : linesMap.get(curPage)) {
            y += m_fontSize + 1;
            mCurPageCanvas.drawText(strLine, marginWidth, y, mPaint);
        }
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(mPaint.getTextSize() / 2);

        int topBarY = 20;
        // 时间
        String time = BookUtil.getCurrentTime();
        mCurPageCanvas.drawText(time, marginWidth, topBarY - 5, paint);
        // 进度绘制
        float fPercent = (float)(mProgress.get(curPage) * 1.0 / m_mbBufLen);
        String strPercent = df.format(fPercent * 100) + "%";
        int nPercentWidth = (int)paint.measureText("999.9%") + 1;
        mCurPageCanvas.drawText(strPercent, mWidth - nPercentWidth, topBarY - 5, paint);
        // 书名
        int booknameWidth = (int)paint.measureText(bookname) + 1;
        mCurPageCanvas.drawText(bookname, mWidth / 2 - booknameWidth / 2, topBarY - 5, paint);
    }

    public Bitmap getmCurPageBitmap() {
        return mCurPageBitmap;
    }

    public Bitmap getmNextPageBitmap() {
        return mNextPageBitmap;
    }

    public int getBookId() {
        return bookId;
    }

}
